/* eslint-disable no-undef */
/* eslint-disable no-prototype-builtins */
/* eslint-disable operator-linebreak */
/**
 * 常用工具集
 */
var tool = {}

// 深拷贝
tool.extend = function(obj) {
  const ss = JSON.parse(JSON.stringify(obj))
  return ss
}

// 倒计时器
/**
  * 倒计时器,该函数将返回一个countdown对象.
  * countdown对象拥有stop(),restart(),start(),done(callback),timeout()方法
  * 注意
  * 1.最后一次为0
  * 2.首次执行必定在延时之后
  * 3.二个参数必须为 number,不然会一直执行
  *
  * 参数
  * @param  {number} n        [倒数读秒]
  * @param  {number} interval [间隔]
  *
  * 示例
  * 无无限循环
   var ss = tool.Countdown(-1,1000).done(function (i) {
     console.log(i);
   });

  * 不立即执行
     var ss = tool.Countdown(10,1000).stop().done(function (i) {
     console.log(i);
   });

  * 特定条件停止
     var ss = tool.Countdown(10,1000).done(function (i) {
     console.log(i);
     if (i < 5) {
       this.stop();
     };
   });
  */
tool.countdown = function(n, interval) {
  interval = interval || 1000
  var countdown = {
    idx: 0,
    max: n,
    i: n,
    callback: function() {},
    stop: function() {
      clearTimeout(this.idx)
      return this
    },
    restart: function() {
      this.i = this.max
      this.timeout()
      return this
    },
    start: function() {
      this.timeout()
      return this
    },
    timeout: function() {
      var self = this
      self.idx = setTimeout(function() {
        // 当 tool.countdown(-1,1000) 时可以一直执行
        if (self.i === 0) {
          return self
        }

        self.i--
        self.timeout()
        self.callback.apply(countdown, [self.i])
      }, interval)
      return self
    },
    done: function(callback) {
      this.callback = callback
      return this
    },
  }
  countdown.timeout()
  return countdown
}

// 快速排序 min-max
/**
  * 快速排序 min-max
  * by oTwo 2014年6月17日 13:33:29
  * @param  {array} d [description]
  * @return {array}
  *
  * ps:不改变原集合
  */
tool.quickSort = function(d) {
  if (d.length <= 1) {
    return d
  }

  var k = d[0]
  var big = []
  var small = []
  var i
  var len
  for (i = 1, len = d.length; i < len; i++) {
    if (d[i] < k) {
      small.push(d[i])
    } else {
      big.push(d[i])
    }
  }
  small = tool.quickSort(small)
  big = tool.quickSort(big)

  return [].concat(small, k, big)
}

// 按KEY从小到大排序对象数组(JSON),不支持多层
tool.sortByKey = function(arr, key) {
  return arr.sort(function(a, b) {
    if (a[key] < b[key]) {
      return -1
    }
    if (a[key] > b[key]) {
      return 1
    }
    return 0
  })
}

// 生成指定范围内的随机整数
/**
  * 生成指定范围内的随机整数
  * by oTwo 2014年6月17日 13:33:35
  * @param  {number} begin [开始范围,默认 100, 可选]
  * @param  {number} end   [结束范围,默认 0, 可选]
  * @return {int}      [随机数]
  *
  * ps:把begin作为大数的原因是可以只写一个参数.roll(1000) === roll(1000,0)
  */
tool.roll = function(begin, end) {
  begin = isNaN(begin - 0) ? 100 : begin
  end = isNaN(end - 0) ? 0 : end
  if (begin < end) {
    var ss = begin
    begin = end
    end = ss
  }

  var r = Math.random()
  r = r * (begin - end + 1) + end
  r = parseInt(r, 10)
  return r
}

// 取得地址档中GET的参数
/**
  * 取得地址档中GET的参数
  * @return {JSON} [description]
  */
tool.request = function() {
  var request = {}
  var hash = ''
  var ss
  hash = window.location.search
  hash = hash.substr(1)

  // 在这里返回 undefined 要比返回空对象好一点,取值我们更容易发现出了什么问题
  if (!hash) {
    return
  }

  hash = decodeURIComponent(hash)
  hash = hash.split(/&/g)
  for (var f1 in hash) {
    ss = hash[f1].split(/=/g)
    request[ss[0]] = ss[1]
  }
  return request
}

// 格式化成时间字符串
// 通过moment.js我们可以更方便的操作"时间",但在打包时会增加200k
// 如果不是特别频繁的操作,建议不要引入
/**
  * 格式化成时间字符串 简版,依赖 tool.pad
  * @param  {date/str/number} date   [时间对像,或能转为时间对像字符串/数字]
  * @param  {str} format ['Y年M月D日 hh:mm:ss']
  * @return {str}
  */
tool.formatDate = function(date, format) {
  var d = new Date(date)
  var map = {
    Y: d.getFullYear(),
    M: d.getMonth() + 1,
    D: d.getDate(),
    hh: d.getHours(),
    mm: d.getMinutes(),
    ss: d.getSeconds(),
  }

  // 从左边补齐二位
  for (var f2 in map) {
    map[f2] = map[f2].toString().padStart(2, '0')
  }

  for (var f1 in map) {
    format = format.replace(f1, map[f1])
  }
  return format
}

// 进入全屏
tool.requestFullScreen = function() {
  var de = document.documentElement
  if (de.requestFullscreen) {
    de.requestFullscreen()
  } else if (de.mozRequestFullScreen) {
    de.mozRequestFullScreen()
  } else if (de.webkitRequestFullScreen) {
    de.webkitRequestFullScreen()
  }
}

// 退出全屏
tool.exitFullscreen = function() {
  var de = document
  if (de.exitFullscreen) {
    de.exitFullscreen()
  } else if (de.mozCancelFullScreen) {
    de.mozCancelFullScreen()
  } else if (de.webkitCancelFullScreen) {
    de.webkitCancelFullScreen()
  }
}

// ----  类型判断  -------------------------------------------------------------
/**
 * 判断两个对象是否完全相等
 * @param {Object} obj1 - 对象1
 * @param {Object} obj2 - 对象2
 * @returns {boolean} - 如果两个对象完全相等则返回 true，否则返回 false
 * @example
 * const obj1 = {name: 'Alice', age: 20, hobbies: ['reading', 'swimming']};
 * const obj2 = {name: 'Alice', age: 20, hobbies: ['reading', 'swimming']};
 * const obj3 = {name: 'Bob', age: 25, hobbies: ['reading', 'swimming']};
 * const obj4 = {name: 'Alice', age: 20, hobbies: ['reading', 'running']};
 *
 * console.log(isEqual(obj1, obj2)); // true
 * console.log(isEqual(obj1, obj3)); // false
 * console.log(isEqual(obj1, obj4)); // false
 */
tool.isEqual = function(obj1, obj2) {
  // 判断类型是否相同
  if (typeof obj1 !== typeof obj2) {
    return false
  }

  // 判断是否为对象或数组
  if (typeof obj1 === 'object') {
    // 判断是否为数组
    if (Array.isArray(obj1) !== Array.isArray(obj2)) {
      return false
    }

    // 判断对象或数组的属性数量是否相同
    if (Object.keys(obj1).length !== Object.keys(obj2).length) {
      return false
    }

    // 递归比较对象或数组的属性和属性值是否相同
    for (let key in obj1) {
      if (!isEqual(obj1[key], obj2[key])) {
        return false
      }
    }
    return true
  }

  // 判断基本类型的值是否相同
  return obj1 === obj2
}

/**
  * 1 所有可以转为 false 的值 都是"空".
  * 2 深度检测对象,如果对象的所有值都是"空"则该对象是"空"
  *
  * by oTwo 2016年10月25日 11:54:57
  * @return {Boolean}   [description]
  */
tool.isEmpty = function(d) {
  if (typeof d !== 'object') {
    return !d
  }
  var ss = true
  var f1
  for (f1 in d) {
    if (typeof d[f1] === 'object') {
      ss = tool.isEmpty(d[f1])
    } else {
      ss = !d[f1]
    }

    if (ss === false) {
      return false
    }
  }
  return true
}

tool.isURL = function(str_url) {
  var strRegex =
     `^((https|http|ftp|rtsp|mms)?://)?(([0-9a-z_!~*'().&=+$%-]+: )?[0-9a-z_!~*'().&=+$%-]+@)?(([0-9]{1,3}.){3}[0-9]{1,3}|([0-9a-z_!~*'()-]+.)*([0-9a-z][0-9a-z-]{0,61})?[0-9a-z].[a-z]{2,6})(:[0-9]{1,4})?((/?)|(/[0-9a-z_!~*'().;?:@&=+$,%#-]+)+/?)$`
  var re = new RegExp(strRegex)

  // re.test()
  if (re.test(str_url)) {
    return true
  } else {
    return false
  }
}

// 是否为验证码
tool.isCode = function(code) {
  var reg = /^[\d]{6}$/
  return reg.test(code)
}

// 是否为手机
tool.isPhone = function(phone) {
  var reg = /^1[2345789]\d{9}$/
  return reg.test(phone)
}

// 是否为邮箱
tool.isEmail = function(email) {
  var reg =
     /^([a-zA-Z0-9]+[_|\_|\.]?)*[a-zA-Z0-9]+@([a-zA-Z0-9]+[_|\_|\.]?)*[a-zA-Z0-9]+\.[a-zA-Z]{2,3}$/
  return reg.test(email)
}

// 验证身份证信息
tool.isCert = function(val) {
  const reg = new RegExp(
    /^[1-9]\d{5}(19|20)\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/,
  )

  const card = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2]
  const cardX = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2']
  let last = 0
  let sum = 0
  if (!reg.test(val)) {
    return false
  }

  // 校验位识别
  for (let i = 0, l = val.length; i < l; i++) {
    if (i < val.length - 1) {
      sum += val[i] * card[i]
    }
    if (i === val.length - 1) {
      last = val[i]
    }
  }
  return cardX[sum % 11] === last
}

// 统一社会信用代码
tool.isCreditCode = function(val) {
  const reg = /^([0-9A-HJ-NPQRTUWXY]{2}\d{6}[0-9A-HJ-NPQRTUWXY]{10})$/
  return reg.test(val)
}

tool.isPC = function() {
  var userAgentInfo = navigator.userAgent
  var Agents = [
    'Android',
    'iPhone',
    'SymbianOS',
    'Windows Phone',
    'iPad',
    'iPod',
  ]
  var flag = true
  for (var v = 0; v < Agents.length; v++) {
    if (userAgentInfo.indexOf(Agents[v]) > 0) {
      flag = false
      break
    }
  }
  return flag
}

tool.isIOS = function() {
  var u = navigator.userAgent
  var isIOS = Boolean(u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/))
  return isIOS
}

/**
  * 判断案例库的平台是否为微信
  * @author gaolei6
  * @time 2016-09-18
  * @return String
  */
tool.isWx = function() {
  var ua = navigator.userAgent
  var pattern_equipent = /MicroMessenger/
  if (pattern_equipent.test(ua)) {
    // 微信客户端
    return true
  }

  return false
}

/**
  * 判断案例库的平台是否为微博
  * @author gaolei6
  * @time 2016-09-18
  * @return String
  */
tool.isWb = function() {
  var ua = navigator.userAgent
  var pattern_weibo = /weibo/
  if (pattern_weibo.test(ua)) {
    // 微博客户端
    return true
  }
  return false
}

// ----  类型转换  -------------------------------------------------------------

// 将 Byte 转为 K/m等 单位
tool.toKB = function(int) {
  int = int / 1024
  if (int < 1024) {
    return `${Math.ceil(int)} K`
  }

  int = int / 1024
  if (int < 1024) {
    return `${Math.ceil(int)} M`
  }
}

// 整数 千分位逗号
// todo 数字 千分位逗号
tool.toThousands = function(num) {
  if (!num) {
    return ''
  }
  if (isNaN(num - 0)) {
    console.log('num', num)
    return num
  }

  const ss = num.toString().split('.')
  let str = ss[0].toString().replace(/^-?\d+/g, (m) => {
    return m.replace(/(?=(?!\b)(\d{3})+$)/g, ',')
  })
  if (ss[1]) {
    str += `.${ss[1]}`
  }
  return str
}
tool.toThousandsTable = function(row, column, cellValue, index) {
  cellValue = cellValue - 0
  if (isNaN(cellValue)) {
    return '0.00'
  }
  if (cellValue === 0) {
    return '0.00'
  }
  cellValue = cellValue.toFixed(2)
  const ss = cellValue.toString().split('.')
  let str = ss[0].toString().replace(/^-?\d+/g, (m) => {
    return m.replace(/(?=(?!\b)(\d{3})+$)/g, ',')
  })
  if (ss[1]) {
    str += `.${ss[1]}`
  }
  return str
}

// 将数组转为树
// tool.arrToTree(res.data, {id: 'id', pid: 'pid', children: 'children'})
// 返回的是个数组,数组其中的对象为树结构
tool.arrToTree = function(data, config = {}) {
  var id = config.id || 'id'
  var pid = config.pid || 'pid'
  var children = config.children || 'children'
  var idMap = {}
  var jsonTree = []
  data.forEach(function(v) {
    idMap[v[id]] = v
  })
  data.forEach(function(v) {
    var parent = idMap[v[pid]]
    if (parent) {
      !parent[children] && (parent[children] = [])
      parent[children].push(v)
    } else {
      jsonTree.push(v)
    }
  })
  return jsonTree
}

// 将树转为数组
// tool.treeToArr(res.data)
// tool.treeToArr(res.data,{ children: 'children' })
// 返回的是个二组数组
tool.treeToArr = function(data, config = { children: 'children' }, pid) {
  data = tool.extend(data)
  var arr = []
  data.forEach(function(item) {
    let d = tool.extend(item)
    let children = item[config.children]
    delete d[config.children]
    d[config.pid] = pid
    arr.push(d)

    if (children && Array.isArray(children)) {
      arr = arr.concat(tool.treeToArr(children, config, item.id))
    }
  })
  return arr
}

// 将数组转为对象
tool.arrToObj = function(data, key) {
  let ss = []
  for (let item of data) {
    ss[key] = item[key]
  }
  return ss
}

// ----  表单校验  -------------------------------------------------------------

// { validator: this.$tool.validateCreditCode, trigger: 'blur',message:'统一社会信用代码校验错误' }
tool.validateCreditCode = (rule, value, callback) => {
  if (tool.isCreditCode(value)) {
    callback()
  } else {
    callback(new Error(rule.message))
  }
}

export default tool

